// ----------------------------------------------------------------------------
// atomic_intrinsic.apple.h
// ----------------------------------------------------------------------------
#ifndef FW_ATOMIC_INTRINSIC_APPLE_H
#define FW_ATOMIC_INTRINSIC_APPLE_H
#include	<libkern/OSAtomic.h>

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_SET(volatile int32_t* p, int32_t v)
{
    while(true)
    {
        int32_t oldvalue = *p;
        if(OSAtomicCompareAndSwapIntBarrier(oldvalue,v,p))
        {
            return oldvalue;
        }
    }
	return 0;
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_GET(volatile int32_t* p)
{
    while(true)
    {
        int32_t value = *p;
        if(OSAtomicCompareAndSwapIntBarrier(value,value,p))
        {
            return value;
        }
	}
    return 0;
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_CAS(volatile int32_t* p, int32_t c, int32_t s)
{
    int32_t value = *p;
    OSAtomicCompareAndSwapIntBarrier(c,s,p);
    return value;
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_INC(volatile int32_t* p)
{
	return OSAtomicIncrement32Barrier(p);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_INC_PREVALUE(volatile int32_t* p)
{
	int32_t oldvalue;
	do
	{
		oldvalue = *p;
	} while(!OSAtomicCompareAndSwapIntBarrier(oldvalue,(oldvalue+1),p));
	return oldvalue;
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_DEC(volatile int32_t* p)
{
	return OSAtomicDecrement32Barrier(p);
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_DEC_PREVALUE(volatile int32_t* p)
{
	int32_t oldvalue;
	do
	{
		oldvalue = *p;
	} while(!OSAtomicCompareAndSwapIntBarrier(oldvalue,(oldvalue-1),p));
	return oldvalue;
}

FW_FORCE_INLINE int32_t FW_ATOMIC_CORE_IMPL_ATOMIC_ADD(volatile int32_t* p, int32_t v)
{
	int32_t oldvalue;
	do
	{
		oldvalue = *p;
	} while(!OSAtomicCompareAndSwapIntBarrier(oldvalue,(oldvalue+v),p));
	return oldvalue;
}

#if defined(FW_TARGET_64BIT)
FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_SET64(volatile int64_t* p, int64_t v)
{
    while(true)
    {
        int64_t oldvalue = *p;
        if(OSAtomicCompareAndSwap64Barrier(oldvalue,v,p))
        {
            return oldvalue;
        }
    }
	return 0;
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_GET64(volatile int64_t* p)
{
    while(true)
    {
        int64_t value = *p;
        if(OSAtomicCompareAndSwap64Barrier(value,value,p))
        {
            return value;
        }
	}
    return 0;
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_CAS64(volatile int64_t* p, int64_t c, int64_t s)
{
    int64_t value = *p;
    OSAtomicCompareAndSwap64Barrier(c,s,p);
    return value;
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_INC64(volatile int64_t* p)
{
	return OSAtomicIncrement64Barrier(p);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_INC_PREVALUE64(volatile int64_t* p)
{
	int64_t oldvalue;
	do
	{
		oldvalue = *p;
	} while(!OSAtomicCompareAndSwap64Barrier(oldvalue,(oldvalue+1),p));
	return oldvalue;
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_DEC64(volatile int64_t* p)
{
	return OSAtomicDecrement64(p);
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_DEC_PREVALUE64(volatile int64_t* p)
{
	int64_t oldvalue;
	do
	{
		oldvalue = *p;
	} while(!OSAtomicCompareAndSwap64Barrier(oldvalue,(oldvalue-1),p));
	return oldvalue;
}

FW_FORCE_INLINE int64_t FW_ATOMIC_CORE_IMPL_ATOMIC_ADD64(volatile int64_t* p, int64_t v)
{
	int64_t oldvalue;
	do
	{
		oldvalue = *p;
	} while(!OSAtomicCompareAndSwap64Barrier(oldvalue,(oldvalue+v),p));
	return oldvalue;
}
#endif // FW_TARGET_64BIT
#endif // FW_ATOMIC_INTRINSIC_APPLE_H

